package com.searchtree.twofourtree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import com.searchtree.main.Performance;
import com.searchtree.main.Utilities;
import com.searchtree.tree.AbstractNode;
import com.searchtree.tree.LeafNode;

public class TwoFourTreeNode extends AbstractNode {

	private ArrayList<String> keys;
	private ArrayList<AbstractNode> nodes;
	private Performance performance = Performance.getInstance();

	/**
	 * Constructor for TwoFourTreeNode Initializes the arraylist with the keys
	 * and the array of AbstractNodes to hold the children of the items
	 */
	public TwoFourTreeNode() {
		performance.addToNumberOfAssignments(2);
		keys = new ArrayList<String>(3);
		nodes = new ArrayList<AbstractNode>(4);
	}

	/**
	 * Constructor for TwoFourTreeNode Initializes the arraylist with the keys
	 * and the array of AbstractNodes to hold the children of the items
	 */
	public TwoFourTreeNode(String key) {
		this();
		addKey(key);
	}

	/**
	 * Constructor for TwoFourTreeNode Initializes the arraylist with the keys
	 * and the array of AbstractNodes to hold the children of the items
	 */
	public TwoFourTreeNode(String key, AbstractNode leftChild,
			AbstractNode rightChild) {
		this(key);
		addChild(leftChild);
		addChild(rightChild);
	}

	/**
	 * Adds a key to the node.
	 * 
	 * @param key
	 *            , the key to be inserted.
	 */
	public void addKey(String key) {
		if (keys.isEmpty()) {
			addChild(new LeafNode());
		}
		keys.add(key);
		Collections.sort(keys);
		nodes.add(keys.indexOf(key) + 1, new LeafNode());
	}

	/**
	 * Getter for all the nodes
	 * 
	 * @return the array with all the child Nodes
	 */
	public ArrayList<AbstractNode> getChildren() {
		return this.nodes;
	}

	/**
	 * Checks wheter the Node is a four Node or not.
	 * 
	 * @return
	 */
	public boolean isFourNode() {
		return (keys.size() == 3);
	}

	/**
	 * Getter for the Keys
	 * 
	 * @return the arraylist with the keys
	 */
	public ArrayList<String> getKeys() {
		return this.keys;
	}

	/**
	 * 
	 * @return
	 */
	public String getMiddleKey() {
		return keys.get(1);
	}

	/**
	 * 
	 * @return
	 */
	public String getRightKey() {
		return keys.get(2);
	}

	/**
	 * 
	 * @return
	 */
	public String getLeftKey() {
		return keys.get(0);
	}

	public boolean childrenAreLeafNodes() {
		performance.addToNumberOfAssignments(2);
		boolean areLeafNodes = true;
		for (int i = 0; i < keys.size(); i++) {
			if (!(nodes.get(i) instanceof LeafNode)) {
				performance.addToNumberOfAssignments(1);
				areLeafNodes = false;
				break;
			}
		}
		return areLeafNodes;
	}

	public void addChild(AbstractNode node) {
		if (node instanceof TwoFourTreeNode) {
			performance.addToNumberOfAssignments(2);
			String key = ((TwoFourTreeNode) node).getLeftKey();
			for (int i = 0; i < keys.size(); i++) {
				performance.addToNumberOfAssignments(1);
				String keyFromN = keys.get(i);
				if (Utilities.compareStringValues(key, keyFromN) == -1) {
					nodes.set(i, node);
					break;
				}
				if ((Utilities.compareStringValues(key, keyFromN) == 1)
						&& (i == keys.size() - 1)) {
					nodes.set(i + 1, node);
				}
			}
		} else {
			nodes.add(node);
		}
	}
	
	/**
	 * Generates a message with some information about this 2-4 tree node
	 * @return String message
	 */
	public String toString(){
		String message = "This 2 4 Tree node contains " + keys.size() + " keys:"; 
		for (Iterator<String> it = keys.iterator(); it.hasNext();) {
			message += "\n	" + it.next();
		}		
		return message;
	}
}
